package com.zf.spring.microservice.service.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpContentCompressor;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;

@Service
public class NettyRunner implements ApplicationContextAware {
	public static ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
	
	private EventLoopGroup bossGroup;
	private EventLoopGroup workerGroup;
	private Channel channel;

	@Value("${server.port:9000}")
	int port;

	@Value("${server.ioThreadNum:5}")
	int ioThreadNum;

	private static final Logger logger = LoggerFactory
			.getLogger(NettyRunner.class);

	@PostConstruct
	public void start() throws InterruptedException {
		logger.debug("begin to start rpc server");
		
		// Configure the server.
		bossGroup = new NioEventLoopGroup(1);
		workerGroup = new NioEventLoopGroup(ioThreadNum);

		ServerBootstrap b = new ServerBootstrap();
		b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
				.handler(new LoggingHandler(LogLevel.INFO))
				.childHandler(new ChannelInitializer<SocketChannel>() {

					@Override
					protected void initChannel(SocketChannel ch) throws Exception {
						ChannelPipeline p = ch.pipeline();
						p.addLast(new HttpRequestDecoder());
						p.addLast(new HttpResponseEncoder());
						p.addLast(new HttpContentCompressor());
						p.addLast(new NettyServerHandler());
					}

});

		channel = b.bind(port).sync().channel();
		logger.debug("Netty server listening on port " + port
				+ " and ready for connections...");
	}

	@PreDestroy
	public void stop() {
		try {
			logger.debug("destroy server resources");
			if (null == channel) {
				logger.debug("server channel is null");
			}
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
			channel.closeFuture().syncUninterruptibly();
			bossGroup = null;
			workerGroup = null;
			channel = null;
		} catch (Exception e) {
			logger.warn(e.getMessage(), e);
		}
	}

	@Override
	public void setApplicationContext(ApplicationContext ctx)
			throws BeansException {
		
	}
}
